package com.hs.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.hs.entity.dto.UpdatePassword;
import com.hs.entity.dto.User;
import com.hs.entity.vo.request.ConfirmResetVO;
import com.hs.entity.vo.request.EmailRegisterVO;
import com.hs.entity.vo.request.EmailResetVO;
import com.hs.mapper.UserMapper;
import com.hs.service.UserService;

import com.hs.utils.Const;
import com.hs.utils.FlowUtils;
import jakarta.annotation.Resource;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    AmqpTemplate amqpTemplate;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    FlowUtils utils;

    @Resource
    PasswordEncoder encoder;
    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = this.findUserByUsernameOrEmail(username);
        if(user == null) {
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        return org.springframework.security.core.userdetails.User
                .withUsername(username)
                .password(user.getPassword())
                .roles(String.valueOf(user.getRole()))
                .build();
    }
    public User findUserByUsernameOrEmail(String text) {
        return this.query()
                .eq("username",text).or()
                .eq("email",text)
                .one();
    }

    @Override
    public String registerEmailVerifyCode(String type, String email, String ip) {

//        synchronized (ip.intern()) {
            if(!this.verifyLimit(ip))
                return "请求频繁，请稍后再试";
            SecureRandom random = new SecureRandom();
//            Random random = new Random();
            int code = random.nextInt(899999)+100000;
            Map<String,Object> data= Map.of("type",type,"email",email,"code",code);
            amqpTemplate.convertAndSend("mail",data);
            stringRedisTemplate.opsForValue()
                    .set(Const.VERIFY_EMAIL_DATA+email,String.valueOf(code),3, TimeUnit.MINUTES);
            return null;
//        }
    }

    @Override
    public String resetConfirm(ConfirmResetVO vo) {
        String email = vo.getEmail();
        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA+email);
        if(code == null) return "请先获取验证码";
        if(!code.equals(vo.getCode())) return "验证码错误，请重新输入";
        return null;
    }

    @Override
    public String resetEmailUserPassword(EmailResetVO vo) {
        String email = vo.getEmail();
        String verify=this.resetConfirm(new ConfirmResetVO(email,vo.getCode()));
        if(verify!=null) return verify;
        String password = encoder.encode(vo.getPassword());
        boolean update = this.update().eq("email",email).set("password",password).update();
        if(update) {
            stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA+email);
        }
        return null;
    }

    @Override
    public PageInfo<User> selectUserList(Integer pageNum ,String keywords) {

        PageHelper.startPage(pageNum,5);

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

        if (keywords != null && !keywords.isEmpty()) {
            queryWrapper.like("username", keywords);  // 根据用户名进行模糊查询
        }

        List<User> userList = userMapper.selectList(queryWrapper);
        return new PageInfo<>(userList);
    }

    @Override
    public User userByUsername(String username) {

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);  // 根据用户名查找

        return userMapper.selectOne(queryWrapper);
    }


    @Override
    public boolean updatePassword(UpdatePassword dto) {
        // 1. 根据用户名查询用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, dto.getUsername());
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
        if (user == null) {
            return false;
        }

        // 2. 验证原密码是否正确
        if (!encoder.matches(dto.getOldPassword(), user.getPassword())) {
            return false;
        }

        // 3. 更新新密码
        LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(User::getId, user.getId())
                .set(User::getPassword, encoder.encode(dto.getNewPassword()));


        return userMapper.update(null,updateWrapper) > 0;
    }

    @Override
    public String registerEmailUser(EmailRegisterVO vo) {
        String email = vo.getEmail();
        String username = vo.getUsername();
        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA+email);
        if(code == null) return "请先获取验证码";
        if(!code.equals(vo.getCode())) return "验证码输入错误，请重新输入";
        if(this.existsUserByEmail(email)) return "此电子邮件已被其他用户注册";
        if(this.existsUserByUsername(username)) return "此用户已被其他人注册";
        String password = encoder.encode(vo.getPassword());
        User user = new User(null,username,password,email,null,
                null,null,null, LocalDateTime.now(),null,3,null);
        if(this.save(user)){
            stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA+email);
            return null;
        }else {
            return "内部错误，请联系管理员";
        }
    }

    private boolean existsUserByEmail(String email) {
        return this.baseMapper.exists(Wrappers.<User>query().eq("email",email));
    }

    private boolean existsUserByUsername(String username) {
        return this.baseMapper.exists(Wrappers.<User>query().eq("username",username));
    }

    private boolean verifyLimit(String ip) {
        String key  = Const.VERIFY_EMAIL_DATA+ip;

        return utils.limitOnceCheck(key,60);
    }
}
